 /*******************************************************************************
  * Copyright (c) 2005, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
  *
  * Contributors:
  * IBM Corporation - initial API and implementation
  *******************************************************************************/
 package org.eclipse.ui.internal;

 import org.eclipse.core.runtime.IConfigurationElement;
 import org.eclipse.core.runtime.IStatus;
 import org.eclipse.core.runtime.dynamichelpers.IExtensionTracker;
 import org.eclipse.jface.action.ContributionManager;
 import org.eclipse.jface.action.IAction;
 import org.eclipse.jface.resource.ImageDescriptor;
 import org.eclipse.osgi.util.NLS;
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.layout.FillLayout;
 import org.eclipse.swt.widgets.Composite;
 import org.eclipse.ui.IKeyBindingService;
 import org.eclipse.ui.IMemento;
 import org.eclipse.ui.IViewPart;
 import org.eclipse.ui.IViewReference;
 import org.eclipse.ui.IWorkbenchPage;
 import org.eclipse.ui.IWorkbenchPart;
 import org.eclipse.ui.IWorkbenchPart2;
 import org.eclipse.ui.IWorkbenchPart3;
 import org.eclipse.ui.PartInitException;
 import org.eclipse.ui.PlatformUI;
 import org.eclipse.ui.internal.misc.StatusUtil;
 import org.eclipse.ui.internal.misc.UIStats;
 import org.eclipse.ui.internal.registry.ViewDescriptor;
 import org.eclipse.ui.internal.util.Util;
 import org.eclipse.ui.menus.IMenuService;
 import org.eclipse.ui.part.IWorkbenchPartOrientation;
 import org.eclipse.ui.statushandlers.StatusManager;
 import org.eclipse.ui.views.IViewDescriptor;
 import org.eclipse.ui.views.IViewRegistry;

 class ViewReference extends WorkbenchPartReference implements IViewReference {

     /**
      *
      */
     private final ViewFactory factory;

     String secondaryId;

     private IMemento memento;

     private ViewActionBuilder actionBuilder;

     public ViewReference(ViewFactory factory, String id, String secondaryId,
             IMemento memento) {
         super();
         this.memento = memento;
         this.factory = factory;
         ViewDescriptor desc = (ViewDescriptor) this.factory.viewReg.find(id);
         ImageDescriptor iDesc = null;
         String title = null;
         if (desc != null) {
             iDesc = desc.getImageDescriptor();
             title = desc.getLabel();
         }

         String name = null;

         if (memento != null) {
             name = memento.getString(IWorkbenchConstants.TAG_PART_NAME);
             IMemento propBag = memento.getChild(IWorkbenchConstants.TAG_PROPERTIES);
             if (propBag != null) {
                 IMemento[] props = propBag
                         .getChildren(IWorkbenchConstants.TAG_PROPERTY);
                 for (int i = 0; i < props.length; i++) {
                     propertyCache.put(props[i].getID(), props[i].getTextData());
                 }
             }
         }
         if (name == null) {
             name = title;
         }

         init(id, title, "", iDesc, name, ""); //$NON-NLS-1$//$NON-NLS-2$
 this.secondaryId = secondaryId;
     }

     protected PartPane createPane() {
         return new ViewPane(this, this.factory.page);
     }

     /*
      * (non-Javadoc)
      *
      * @see org.eclipse.ui.internal.WorkbenchPartReference#dispose()
      */
     protected void doDisposePart() {
         IViewPart view = (IViewPart) part;
         if (view != null) {
             // Free action bars, pane, etc.
 PartSite site = (PartSite) view.getSite();
             ViewActionBars actionBars = (ViewActionBars) site.getActionBars();
             //
 // 3.3 start
 //
 IMenuService menuService = (IMenuService) site
                     .getService(IMenuService.class);
             menuService.releaseContributions((ContributionManager) site.getActionBars()
                     .getMenuManager());
             menuService.releaseContributions((ContributionManager) site.getActionBars()
                     .getToolBarManager());
             // 3.3 end
 actionBars.dispose();
             
             // and now dispose the delegates since the
 // PluginActionContributionItem
 // can no longer do that
 actionBuilder.dispose();
             actionBuilder = null;

             // Free the site.
 site.dispose();
         }

         super.doDisposePart();
     }

     /*
      * (non-Javadoc)
      *
      * @see org.eclipse.ui.IWorkbenchPartReference#getPage()
      */
     public IWorkbenchPage getPage() {
         return this.factory.page;
     }

     /*
      * (non-Javadoc)
      *
      * @see org.eclipse.ui.internal.WorkbenchPartReference#getRegisteredName()
      */
     public String getRegisteredName() {
         if (part != null && part.getSite() != null) {
             return part.getSite().getRegisteredName();
         }

         IViewRegistry reg = this.factory.viewReg;
         IViewDescriptor desc = reg.find(getId());
         if (desc != null) {
             return desc.getLabel();
         }
         return getTitle();
     }

     protected String computePartName() {
         if (part instanceof IWorkbenchPart2) {
             return super.computePartName();
         } else {
             return getRegisteredName();
         }
     }

     protected String computeContentDescription() {
         if (part instanceof IWorkbenchPart2) {
             return super.computeContentDescription();
         } else {
             String rawTitle = getRawTitle();

             if (!Util.equals(rawTitle, getRegisteredName())) {
                 return rawTitle;
             }

             return ""; //$NON-NLS-1$
 }
     }

     /*
      * (non-Javadoc)
      *
      * @see org.eclipse.ui.IViewReference
      */
     public String getSecondaryId() {
         return secondaryId;
     }

     /*
      * (non-Javadoc)
      *
      * @see org.eclipse.ui.IViewReference#getView(boolean)
      */
     public IViewPart getView(boolean restore) {
         return (IViewPart) getPart(restore);
     }

     /*
      * (non-Javadoc)
      *
      * @see org.eclipse.ui.IViewReference#isFastView()
      */
     public boolean isFastView() {
         return this.factory.page.isFastView(this);
     }

     /**
      * Wrapper for restoring the view. First, this delegates to
      * busyRestoreViewHelper to do the real work of restoring the view. If
      * unable to restore the view, this method tries to substitute an error part
      * and return success.
      *
      * @param factory
      * TODO
      * @return
      */
     protected IWorkbenchPart createPart() {

         // Check the status of this part

         IWorkbenchPart result = null;
         PartInitException exception = null;

         // Try to restore the view -- this does the real work of restoring the
 // view
 //
 try {
             result = createPartHelper();
         } catch (PartInitException e) {
             exception = e;
         }

         // If unable to create the part, create an error part instead
 // and pass the error to the status handling facility
 if (exception != null) {
             IStatus partStatus = exception.getStatus();
             IStatus displayStatus = StatusUtil.newStatus(partStatus,
                     WorkbenchMessages.ViewFactory_initException);
             IStatus logStatus = StatusUtil
                     .newStatus(
                             partStatus,
                             NLS
                                     .bind(
                                             "Unable to create view ID {0}: {1}", getId(), partStatus.getMessage())); //$NON-NLS-1$

             // Pass the error to the status handling facility
 StatusManager.getManager().handle(logStatus);
             StatusManager.getManager()
                     .handle(displayStatus, StatusManager.SHOW);

             IViewDescriptor desc = factory.viewReg.find(getId());
             String label = getId();
             if (desc != null) {
                 label = desc.getLabel();
             }

             ErrorViewPart part = new ErrorViewPart(displayStatus);

             PartPane pane = getPane();
             ViewSite site = new ViewSite(this, part, factory.page, getId(),
                     PlatformUI.PLUGIN_ID, label);
             site.setActionBars(new ViewActionBars(factory.page.getActionBars(),
                     site, (ViewPane) pane));
             try {
                 part.init(site);
             } catch (PartInitException e) {
                 StatusUtil.handleStatus(e, StatusManager.SHOW
                         | StatusManager.LOG);
                 return null;
             }
             part.setPartName(label);

             Composite parent = (Composite) pane.getControl();
             Composite content = new Composite(parent, SWT.NONE);
             content.setLayout(new FillLayout());

             try {
                 part.createPartControl(content);
             } catch (Exception e) {
                 content.dispose();
                 StatusUtil.handleStatus(e, StatusManager.SHOW
                         | StatusManager.LOG);
                 return null;
             }

             result = part;
         }

         return result;
     }

     private IWorkbenchPart createPartHelper() throws PartInitException {

         IWorkbenchPart result = null;

         IMemento stateMem = null;
         if (memento != null) {
             stateMem = memento.getChild(IWorkbenchConstants.TAG_VIEW_STATE);
         }

         IViewDescriptor desc = factory.viewReg.find(getId());
         if (desc == null) {
             throw new PartInitException(
                     WorkbenchMessages.ViewFactory_couldNotCreate);
         }

         // Create the part pane
 PartPane pane = getPane();

         // Create the pane's top-level control
 pane.createControl(factory.page.getClientComposite());

         String label = desc.getLabel(); // debugging only

         // Things that will need to be disposed if an exception occurs (they are
 // listed here
 // in the order they should be disposed)
 Composite content = null;
         IViewPart initializedView = null;
         ViewSite site = null;
         ViewActionBars actionBars = null;
         // End of things that need to be explicitly disposed from the try block

         try {
             IViewPart view = null;
             try {
                 UIStats.start(UIStats.CREATE_PART, label);
                 view = desc.createView();
             } finally {
                 UIStats.end(UIStats.CREATE_PART, view, label);
             }

             if (view instanceof IWorkbenchPart3) {
                 createPartProperties((IWorkbenchPart3)view);
             }
             // Create site
 site = new ViewSite(this, view, factory.page, desc);
             actionBars = new ViewActionBars(factory.page.getActionBars(), site,
                     (ViewPane) pane);
             site.setActionBars(actionBars);

             try {
                 UIStats.start(UIStats.INIT_PART, label);
                 view.init(site, stateMem);
                 // Once we've called init, we MUST dispose the view. Remember
 // the fact that
 // we've initialized the view in case an exception is thrown.
 initializedView = view;

             } finally {
                 UIStats.end(UIStats.INIT_PART, view, label);
             }

             if (view.getSite() != site) {
                 throw new PartInitException(
                         WorkbenchMessages.ViewFactory_siteException, null);
             }
             int style = SWT.NONE;
             if (view instanceof IWorkbenchPartOrientation) {
                 style = ((IWorkbenchPartOrientation) view).getOrientation();
             }

             // Create the top-level composite
 {
                 Composite parent = (Composite) pane.getControl();
                 content = new Composite(parent, style);
                 content.setLayout(new FillLayout());

                 try {
                     UIStats.start(UIStats.CREATE_PART_CONTROL, label);
                     view.createPartControl(content);

                     parent.layout(true);
                 } finally {
                     UIStats.end(UIStats.CREATE_PART_CONTROL, view, label);
                 }
             }

             // Install the part's tools and menu
 {
                 //
 // 3.3 start
 //
 IMenuService menuService = (IMenuService) site
                         .getService(IMenuService.class);
                 menuService.populateContributionManager(
                         (ContributionManager) site.getActionBars()
                                 .getMenuManager(), "menu:" //$NON-NLS-1$
 + site.getId());
                 menuService
                         .populateContributionManager((ContributionManager) site
                                 .getActionBars().getToolBarManager(),
                                 "toolbar:" + site.getId()); //$NON-NLS-1$
 // 3.3 end

                 actionBuilder = new ViewActionBuilder();
                 actionBuilder.readActionExtensions(view);
                 ActionDescriptor[] actionDescriptors = actionBuilder
                         .getExtendedActions();
                 IKeyBindingService keyBindingService = view.getSite()
                         .getKeyBindingService();

                 if (actionDescriptors != null) {
                     for (int i = 0; i < actionDescriptors.length; i++) {
                         ActionDescriptor actionDescriptor = actionDescriptors[i];

                         if (actionDescriptor != null) {
                             IAction action = actionDescriptors[i].getAction();

                             if (action != null
                                     && action.getActionDefinitionId() != null) {
                                 keyBindingService.registerAction(action);
                             }
                         }
                     }
                 }

                 site.getActionBars().updateActionBars();
             }

             // The editor should now be fully created. Exercise its public
 // interface, and sanity-check
 // it wherever possible. If it's going to throw exceptions or behave
 // badly, it's much better
 // that it does so now while we can still cancel creation of the
 // part.
 PartTester.testView(view);

             result = view;

             IConfigurationElement element = (IConfigurationElement) Util.getAdapter(desc,
                     IConfigurationElement.class);
             if (element != null) {
                 factory.page.getExtensionTracker().registerObject(
                         element.getDeclaringExtension(), view,
                         IExtensionTracker.REF_WEAK);
             }
         } catch (Throwable e) {
             if ((e instanceof Error ) && !(e instanceof LinkageError )) {
                 throw (Error ) e;
             }
             
             // An exception occurred. First deallocate anything we've allocated
 // in the try block (see the top
 // of the try block for a list of objects that need to be explicitly
 // disposed)
 if (content != null) {
                 try {
                     content.dispose();
                 } catch (RuntimeException re) {
                     StatusManager.getManager().handle(
                             StatusUtil.newStatus(WorkbenchPlugin.PI_WORKBENCH,
                                     re));
                 }
             }

             if (initializedView != null) {
                 try {
                     initializedView.dispose();
                 } catch (RuntimeException re) {
                     StatusManager.getManager().handle(
                             StatusUtil.newStatus(WorkbenchPlugin.PI_WORKBENCH,
                                     re));
                 }
             }

             if (site != null) {
                 try {
                     site.dispose();
                 } catch (RuntimeException re) {
                     StatusManager.getManager().handle(
                             StatusUtil.newStatus(WorkbenchPlugin.PI_WORKBENCH,
                                     re));
                 }
             }

             if (actionBars != null) {
                 try {
                     actionBars.dispose();
                 } catch (RuntimeException re) {
                     StatusManager.getManager().handle(
                             StatusUtil.newStatus(WorkbenchPlugin.PI_WORKBENCH,
                                     re));
                 }
             }

             throw new PartInitException(WorkbenchPlugin.getStatus(e));
         }

         return result;
     }

     /**
      * The memento is that last view state saved by the workbench.
      *
      * @return the last state that was saved by the workbench. It can return
      * <code>null</code>.
      * @since 3.1.1
      */
     public IMemento getMemento() {
         return memento;
     }
 }

